<?php
namespace app\controller\api;

use app\exception\ErrnoPlus;
use app\validate\CaptchaValidate;
use share\controller\ApiBaseController;
use share\exception\ApiException;
use share\service\CaptchaService;
use share\service\SoftAccessService;
use think\Log;

class CaptchaController extends ApiBaseController{
    
    protected $beforeActionList = [  
        "checkSign" => ["only" => "apply"],
    ];

    public function initValidate(){        
        $this->validate = new CaptchaValidate();
    }

    /**
     * 显示验证码 没有cookie时设置cookie
     */
    public function image_action()
    {
        $ip = request()->ip();
        $hash = request()->param("hash");
        if(empty($hash)){
            trace('no hash given ' . $ip, Log::ERROR);
            throw new ApiException('invalid request',ErrnoPlus::CAPTCHA_INVALID_REQUEST);
        }
        if (!self::checkHash($hash)) {
            $ip = request()->ip();
            trace('hash format error ip: ' . $ip, Log::ERROR);
            throw new ApiException('image error.hash format error ip: ' . $ip, ErrnoPlus::CAPTCHA_INVALID_REQUEST);       
        }        
        $captcha = CaptchaService::getImageHandle($hash);
        $captcha->getImage();
        exit();
    }

    /**
     * 显示验证码 没有cookie时设置cookie
     */
    public function image_info_action()
    {
        $hash = self::makeHash();
        $url = "api/captcha/image";
        $resp = ["hash" => $hash, 'url' => $url];
        return self::ok($resp);
    }

    /**
     * 效验验证码并进行软授权 没有cookie时设置cookie
     */
    public function apply_action()
    {
        $ip = request()->ip();
        $params = $this->check();
        $hash = $params['hash'];
        $code = $params['code'];
        $scene = $params['scene'];
        if (!self::checkHash($params['hash'])) {
            trace('hash format error ip: ' . $ip, Log::ERROR);
            throw new ApiException("invalid request",ErrnoPlus::CAPTCHA_INVALID_REQUEST);     
        }
 
        if (!CaptchaService::check($hash, $code)) {
            throw new ApiException("captcha code error",ErrnoPlus::CAPTCHA_CODE_ERROR);          
        }
        
        $token = SoftAccessService::auth($ip, $scene);
        $resp = ["token" => $token, 'scene' => $scene];
        return self::ok($resp);
    }

    /**
     * 生成hash
     */
    protected static function makeHash()
    {
        $ip = request()->ip();
        $source = sprintf("cookie:%s,%f,%d", $ip, microtime(true), mt_rand(1000, 99999));
        $hash = md5($source);
        $prefix = substr($hash, 20);
        $subfix = substr($hash, 0, 10);
        return sprintf("%s%s%s", $prefix, md5(md5($prefix) . $subfix), $subfix);
    }

    /**
     * 检查hash格式
     */
    public static function checkHash($hash)
    {
        if (strlen($hash) != 54) {
            return false;
        }
        $prefix = substr($hash, 0, 12);
        $sign = substr($hash, 12, 32);
        $subfix = substr($hash, 44);
        $check = md5(md5($prefix) . $subfix);
        return $sign === $check;
    }
}